home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Tools & Apps / Graphics & Imaging / Ultra Dragging 1.0ß1 / UIconDragging.inc1.p < prev    next >
Encoding:
Text File  |  1991-05-24  |  24.5 KB  |  932 lines  |  [TEXT/MPS ]

  1. { UIconDragging.inc1.p}
  2. { Copyright © 1990, 1991 by Apple Computer, Inc. All rights reserved.}
  3.  
  4. {    Change List:
  5.  
  6.         ddmmyy
  7.     KJS    040391    First integration into Tangram UI                
  8.     GAP    010491    Created unit constants and global section
  9.                 and moved declarations for icon dimensions
  10.                 and insets here from the interface.
  11.     GAP    010491    Moved gOffscreenManager global to implementation
  12.                 from the interface.
  13.     GAP    020491    Moved icon height and width back to interface.
  14.     GAP    020491    Fixed infinitely recursive bug in
  15.                 TPlaceByNumber.GetCIconHandle.
  16.     GAP    020491    Moved USES UOffscreenManager to implementation.
  17.     GAP    050491    Factored code of TCIconTracker.ICIconTracker into
  18.                 multiple nested procedures.
  19.     GAP    050491    In TCIconTracker.ICIconTracker changed setting of portRect
  20.                 of fMaxDepthGrafPort from maxDepthGrafPort^.portRect := globRect
  21.                 to use of PortSize and MovePortTo.
  22.     GAP    052491    Made changes to convert window to local coordinate in
  23.                 TInterViewTracker.TrackMouse>>NextView>>ContainsPt so icons
  24.                 can be dragged onto views that are scrolled.
  25.  
  26.  
  27.     End Change List. }
  28.  
  29.  
  30. { ::::::::::::    Interfaces used only by Implementation     :::::::::::: }
  31.  
  32.  
  33. USES
  34.  
  35.     UOffscreenManager;
  36.  
  37.  
  38.  
  39. { ::::::::::::     Unit Constants and Globals     :::::::::::: }
  40.  
  41.  
  42. CONST
  43.  
  44.     kInsetWidth = -2 * kIconWidth;
  45.     kInsetHeight = -2 * kIconHeight;
  46.  
  47.  
  48. VAR
  49.     gOffscreenManager: TOffscreenManager;    { Manages virtual offscreen pixmap for icon dragging. }
  50.  
  51.  
  52.  
  53. { :::::::::::::::     Unit Initialization     :::::::::::::::: }
  54.  
  55.  
  56. {$S AInit}
  57. PROCEDURE InitUIconDragging;
  58.  
  59.     VAR
  60.         offscreenSize: Point;
  61.  
  62.     BEGIN {InitUIconDragging}
  63.  
  64.         gOffscreenManager := NIL;
  65.  
  66.         offscreenSize.h := 5 * kIconWidth;
  67.         offscreenSize.v := 5 * kIconHeight;
  68.         NEW(gOffscreenManager);
  69.         FailNIL(gOffscreenManager);
  70.         gOffscreenManager.IOffscreenManager(offscreenSize);
  71.  
  72.     END; {InitUIconDragging}
  73.  
  74.  
  75. { :::::::::::::     TTrackingView     ::::::::::::::::: }
  76.  
  77.  
  78. {$S ARes}
  79. FUNCTION TTrackingView.GetInterViewTracker (anIconNumber: IconNumber;
  80.                                             offset: Point): TInterViewTracker;
  81.  
  82. {    Return the proper tracker to track a icon for this view. }
  83.  
  84.     BEGIN {TTrackingView.GetInterViewTracker}
  85.         GetInterViewTracker := TInterViewTracker(gNoChanges)    { Default is no tracker }
  86.     END; {TTrackingView.GetInterViewTracker}
  87.  
  88.  
  89. {$S ARes}
  90. PROCEDURE TTrackingView.PlaceIcon (anIconNumber: IconNumber;
  91.                                    aVPoint: VPoint;
  92.                                    sense: IconPlacementSense);
  93.  
  94. {    Place an icon in the view at aVPoint in this view's coordinate system. }
  95.  
  96.     BEGIN {TTrackingView.PlaceIcon}
  97.     {$IFC qDebug}
  98.         WRITELN('TTrackingView.PlaceIcon must be overriden!')
  99.     {$ENDC}
  100.     END; {TTrackingView.PlaceIcon}
  101.  
  102.  
  103. { ::::::::::::::::     TCIconTracker     ::::::::::::::::::: }
  104.  
  105. { $S ASelCommand }
  106. PROCEDURE TCIconTracker.ICIconTracker (itsCmdNumber: CmdNumber;
  107.                                        itsDocument: TDocument;
  108.                                        itsView: TView;
  109.                                        itsScroller: TScroller;
  110.                                        anIcon: CIconHandle);
  111.  
  112.     VAR
  113.     
  114.         anOSImage: TOSImage;
  115.         iconRect: Rect;
  116.  
  117.     PROCEDURE PreInitialization;
  118.     
  119.         BEGIN {PreInitialization}
  120.         
  121.             fFirstTime := FALSE;
  122.             fLastTime := FALSE;
  123.             fThisTrackPoint := gZeroPt;
  124.             fLastTrackPoint := gZeroPt;
  125.             fCIcon := anIcon;
  126.             fScreenLocusRect.topLeft := gZeroPt;
  127.             fScreenLocusRect.botRight := gZeroPt;
  128.             fMaxDepthGrafPort := NIL;
  129.             fUnderIcon := NIL
  130.             
  131.         END; {PreInitialization}
  132.         
  133.     PROCEDURE SetParentGrafPortAndBounds;
  134.  
  135.     {    Set fMaxDepthGrafPort and iconRect as the parent grafport
  136.         and bounds for a TOSImage.                                    }
  137.     
  138.         VAR
  139.         
  140.             globRgn: RgnHandle;
  141.             globRect: Rect;
  142.             globWidth, globHeight: INTEGER;
  143.             theMaxDevice, oldGDevice: GDHandle;
  144.             maxDepthGrafPort: CGrafPtr;
  145.     
  146.         BEGIN {SetParentGrafPortAndBounds}
  147.  
  148.         {    Make a parent grafPort for our OSImage of max depth- See Tech Note #120    }
  149.             globRgn := GetGrayRgn;
  150.             globRect := globRgn^^.rgnBBox;
  151.             globWidth := globRect.right - globRect.left;
  152.             globHeight := globRect.bottom - globRect.top;
  153.             theMaxDevice := GetMaxDevice(globRect);
  154.             oldGDevice := GetGDevice;
  155.             SetGDevice(theMaxDevice);
  156.             maxDepthGrafPort := CGrafPtr(NewPtr(SIZEOF(CGrafPort)));
  157.             OpenCPort(maxDepthGrafPort);
  158.             PortSize(globWidth, globHeight);        { Set PortRect to cover all devices. }
  159.             MovePortTo(globRect.left, globRect.top);
  160.             fMaxDepthGrafPort := GrafPtr(maxDepthGrafPort);
  161.             SetGDevice(oldGDevice);
  162.             
  163.         {    Make sure the iconRect is within the bounds of the corresponding graphics device. }
  164.             iconRect := theMaxDevice^^.gdPMap^^.bounds;
  165.             GlobalToLocal(iconRect.topLeft);
  166.             iconRect.right := iconRect.left + kIconWidth;
  167.             iconRect.bottom := iconRect.top + kIconHeight;
  168.     
  169.         END; {SetParentGrafPortAndBounds}
  170.                 
  171.         
  172.     BEGIN {TCIconTracker.ICIconTracker}
  173.  
  174.     {    Preinitialize instance variables in case of failure.    }
  175.         PreInitialization;
  176.         
  177.         SELF.ICommand(itsCmdNumber, itsDocument, itsView, itsScroller);
  178.  
  179.     {    Calculate and set fMaxDepthGrafPort and iconRect.    }
  180.         SetParentGrafPortAndBounds;
  181.  
  182.     {    Create a TOSImage to store the bits under where the icon
  183.         is plotted, so they can be restored when it moves again.    }
  184.         NEW(anOSImage);
  185.         FailNIL(anOSImage);
  186.         anOSImage.IOSImage(fMaxDepthGrafPort, iconRect);
  187.         fUnderIcon := anOSImage;
  188.  
  189.     END; {TCIconTracker.ICIconTracker}
  190.  
  191.  
  192. {$S ADoCommand}
  193. PROCEDURE TCIconTracker.Free;
  194. OVERRIDE;
  195.  
  196.     BEGIN {TCIconTracker.Free}
  197.         DisposIfHandle(fCIcon);
  198.         FreeIfObject(fUnderIcon);
  199.  
  200. (**** Known Bug: This OUGHT to be necessary, but inclusion will cause the command to crash ***********
  201.  
  202.     {    This goes after FreeIfObject(fUnderIcon) since fUnderIcon
  203.         depends on fMaxDepthGrafPort.                                }
  204.         
  205.         IF fMaxDepthGrafPort <> NIL THEN
  206.             BEGIN
  207.                 CloseCPort(CGrafPtr(fMaxDepthGrafPort));
  208.                 DisposPtr(Ptr(fMaxDepthGrafPort))
  209.             END;
  210.             
  211. ******************************************************************************************************)
  212.             
  213.         INHERITED Free
  214.     END; {TCIconTracker.Free}
  215.  
  216. {$S AFields}
  217. PROCEDURE TCIconTracker.Fields (PROCEDURE DoToField (fieldName: Str255;
  218.                                                      fieldAddr: Ptr;
  219.                                                      fieldType: INTEGER));
  220. OVERRIDE;
  221.  
  222.     BEGIN {TCIconTracker.Fields}
  223.         DoToField('TCIconTracker', NIL, bClass);
  224.         DoToField('fFirstTime', @fFirstTime, bBoolean);
  225.         DoToField('fLastTime', @fLastTime, bBoolean);
  226.         DoToField('fThisTrackPoint', @fThisTrackPoint, bPoint);
  227.         DoToField('fLastTrackPoint', @fLastTrackPoint, bPoint);
  228.         DoToField('fCIcon', @fCIcon, bHandle);
  229.         DoToField('fScreenLocusRect', @fScreenLocusRect, bRect);
  230.         DoToField('fMaxDepthGrafPort', @fMaxDepthGrafPort, bGrafPtr);
  231.         DoToField('fUnderIcon', @fUnderIcon, bObject);
  232.         INHERITED Fields(DoToField);
  233.     END; {TCIconTracker.Fields}
  234.  
  235.  
  236. { Mouse handling }
  237. {$S ADoCommand}
  238. FUNCTION TCIconTracker.TrackMouse (aTrackPhase: TrackPhase;
  239.                                    VAR anchorPoint, previousPoint, nextPoint: VPoint;
  240.                                    mouseDidMove: BOOLEAN): TCommand;
  241. OVERRIDE;
  242.  
  243. {    Note: Subclasses must call this TrackMouse method before executing their TrackMouse code. }
  244.  
  245.     BEGIN {TCIconTracker.TrackMouse}
  246.         TrackMouse := SELF;
  247.         CASE aTrackPhase OF
  248.             trackPress: 
  249.                 fFirstTime := TRUE;
  250.             trackMove: 
  251.                 fFirstTime := FALSE;
  252.             trackRelease: 
  253.                 fLastTime := TRUE
  254.         END
  255.     END; {TCIconTracker.TrackMouse}
  256.  
  257.  
  258. {$S ADoCommand}
  259. PROCEDURE TCIconTracker.CIconTrack (nextPoint: Point);
  260.  
  261.     VAR
  262.     
  263.         currPort: GrafPtr;
  264.         oldOnScreenIconRect: Rect;    { The rectangle around the icon, screen coordinates, last time through the loop.    }
  265.         newOnScreenIconRect: Rect;    { The rectangle around the icon, screen coordinates, this time through the loop.    }
  266.         oldOffScreenIconRect: Rect;    { The rectangle around the icon, offScreen coordinates, last time through the loop.    }
  267.         newOffScreenIconRect: Rect;    { The rectangle around the icon, offScreen coordinates, this time through the loop.    }
  268.  
  269.     PROCEDURE Constrain;
  270.  
  271.     {    We do constraining here because TCommand.TrackConstrain gets called at the wrong time.  }
  272.  
  273.         VAR
  274.             enclosingRect: Rect;
  275.  
  276.         {$IFC qDebug}
  277.             pnState: PenState;
  278.         {$ENDC}
  279.  
  280.         PROCEDURE ConstrainPtToRect;
  281.  
  282.             BEGIN {ConstrainPtToRect}
  283.     
  284.                 IF fThisTrackPoint.h < enclosingRect.left THEN    { Constrain Horizontal }
  285.                     BEGIN
  286.                     {$IFC qDebug}
  287.                         IF gIntenseDebugging THEN
  288.                             WRITELN('Constrained on LEFT ', fThisTrackPoint.h, ' -> ', enclosingRect.left);
  289.                     {$ENDC}
  290.                         fThisTrackPoint.h := enclosingRect.left
  291.                     END
  292.                 ELSE IF fThisTrackPoint.h > enclosingRect.right THEN
  293.                     BEGIN
  294.                     {$IFC qDebug}
  295.                         IF gIntenseDebugging THEN
  296.                             WRITELN('Constrained on RIGHT ', fThisTrackPoint.h, ' -> ', enclosingRect.right);
  297.                     {$ENDC}
  298.                         fThisTrackPoint.h := enclosingRect.right
  299.                     END;
  300.     
  301.                 IF fThisTrackPoint.v < enclosingRect.top THEN    { Constrain Vertical }
  302.                     BEGIN
  303.                     {$IFC qDebug}
  304.                         IF gIntenseDebugging THEN
  305.                             WRITELN('Constrained on TOP ', fThisTrackPoint.v, ' -> ', enclosingRect.top);
  306.                     {$ENDC}
  307.                         fThisTrackPoint.v := enclosingRect.top
  308.                     END
  309.                 ELSE IF fThisTrackPoint.v > enclosingRect.bottom THEN
  310.                     BEGIN
  311.                     {$IFC qDebug}
  312.                         IF gIntenseDebugging THEN
  313.                             WRITELN('Constrained on BOTTOM ', fThisTrackPoint.v, ' -> ', enclosingRect.bottom);
  314.                     {$ENDC}
  315.                         fThisTrackPoint.v := enclosingRect.bottom
  316.                     END
  317.     
  318.             END; {ConstrainPtToRect}
  319.  
  320.         BEGIN {Constrain}
  321.  
  322.             IF fFirstTime THEN
  323.                 fLastTrackPoint := fThisTrackPoint
  324.             ELSE
  325.                 BEGIN
  326.                     enclosingRect := gOffscreenManager.fScreenRect;
  327.                 {    Adjust for the fact that icons are plotted from upper-left corner. }
  328.                     enclosingRect.right := enclosingRect.right - kIconWidth;
  329.                     enclosingRect.bottom := enclosingRect.bottom - kIconHeight;
  330.                 {$IFC qDebug}
  331.                     IF gIntenseDebugging THEN
  332.                         BEGIN
  333.                             GetPenState(pnState);
  334.                             PenMode(patXor);
  335.                             FrameRect(enclosingRect);
  336.                             FrameRect(enclosingRect);
  337.                             SetPenState(pnState)
  338.                         END;
  339.                 {$ENDC}
  340.                     ConstrainPtToRect
  341.                 END
  342.         END; {Constrain}
  343.  
  344.     PROCEDURE CalculateRectangles;
  345.  
  346.     {    Calculate all the requisite rectangles. }
  347.  
  348.         VAR
  349.             offsetPt: Point;
  350.             locusRect: Rect;
  351.  
  352.         BEGIN {CalculateRectangles}
  353.  
  354.             SetRect(newOnScreenIconRect,
  355.                     fThisTrackPoint.h,
  356.                     fThisTrackPoint.v,
  357.                     fThisTrackPoint.h + kIconWidth,
  358.                     fThisTrackPoint.v + kIconHeight);
  359.             SetRect(oldOnScreenIconRect,
  360.                     fLastTrackPoint.h,
  361.                     fLastTrackPoint.v,
  362.                     fLastTrackPoint.h + kIconWidth,
  363.                     fLastTrackPoint.v + kIconHeight);
  364.  
  365.             SetRect(newOffScreenIconRect,
  366.                     -kInsetWidth,
  367.                     -kInsetHeight,
  368.                     -kInsetWidth + kIconWidth,
  369.                     -kInsetHeight + kIconHeight);
  370.  
  371.             offsetPt := fThisTrackPoint;
  372.             SubPt(fLastTrackPoint, offsetPt);
  373.             oldOffScreenIconRect := newOffScreenIconRect;
  374.             OffsetRect(oldOffScreenIconRect, -offsetPt.h, -offsetPt.v);
  375.  
  376.             locusRect := newOnScreenIconRect;
  377.             InsetRect(locusRect, kInsetWidth, kInsetHeight);
  378.  
  379.         {    Note: try aligning bitmaps for extra performance. }
  380.  
  381.             fScreenLocusRect := locusRect;
  382.  
  383.         END; {CalculateRectangles}
  384.  
  385.     PROCEDURE GetLocusFromScreen;
  386.  
  387.     {    Get the pixels around the area where the icon will be and store it in the offscreen fScreenLocusImage. }
  388.     
  389.         VAR
  390.             screenLocusRect : Rect;
  391.  
  392.         BEGIN {GetLocusFromScreen}
  393.             screenLocusRect := fScreenLocusRect;
  394.             gOffscreenManager.CopyBitsFromScreen(screenLocusRect, srcCopy, NIL)
  395.         END; {GetLocusFromScreen}
  396.  
  397.     PROCEDURE GetUnderNewIcon;
  398.  
  399.     {    Get the pixels where the icon will be plotted from fScreenLocusImage and store in the offscreen fUnderIcon. }
  400.  
  401.         VAR
  402.  
  403.             dstRect : Rect;
  404.             savedPort : GrafPtr;
  405.             savedGDevice : GDHandle;
  406.             
  407.     {$IFC qDebug}
  408.             aRect: Rect;
  409.     {$ENDC}
  410.  
  411.         BEGIN {GetUnderNewIcon}
  412.  
  413.             dstRect := fUnderIcon.fDstRect;
  414.             
  415.         {    Save the current grafEnv and set it to this offscreen    }
  416.             GetGrafEnv(savedPort, savedGDevice);
  417.             SetOSGrafEnv(fUnderIcon.fParent, dstRect, fUnderIcon.fOSIP);
  418.  
  419.             gOffscreenManager.CopyBitsTo(fUnderIcon.fOSIp^.portBits, fUnderIcon.fOSIp^.portRect, newOnScreenIconRect, srcCopy, NIL);
  420.  
  421.         {    Restore old port    }
  422.             SetGrafEnv(savedPort, savedGDevice);
  423.  
  424.         {$IFC qDebug}
  425.             IF gIntenseDebugging THEN  { Show, in the upper left of the screen, what's under the icon. }
  426.                 BEGIN
  427.                     SetRect(aRect, 0, 200, kIconWidth, 200 + kIconHeight);  
  428.                     CopyBits(fUnderIcon.fOSIp^.portBits,
  429.                              currPort^.portBits,
  430.                              fUnderIcon.fOSIp^.portRect,
  431.                              aRect, srcCopy,
  432.                              NIL);
  433.                 END;
  434.         {$ENDC}
  435.  
  436.         END; {GetUnderNewIcon}
  437.  
  438.     PROCEDURE RestoreUnderOldIcon;
  439.  
  440.     {    Put the pixels back in fScreenLocusImage where the icon was plotted. }
  441.  
  442.         VAR
  443.  
  444.             savedPort : GrafPtr;
  445.             savedGDevice : GDHandle;
  446.             
  447.         BEGIN {RestoreUnderOldIcon}
  448.  
  449.             gOffscreenManager.CopyBitsFrom(fUnderIcon.fOSIp^.portBits,
  450.                                            fUnderIcon.fOSIp^.portRect,
  451.                                            oldOnScreenIconRect,
  452.                                            srcCopy,
  453.                                            NIL);
  454.  
  455.         END; {RestoreUnderOldIcon}
  456.  
  457.     PROCEDURE RenderIcon;
  458.  
  459.     {    Plot the icon in the offscreen fScreenLocusImage. }
  460.  
  461.         PROCEDURE QuickDrawStuff;
  462.  
  463.             BEGIN {QuickDrawStuff}
  464.                 PlotCIcon(newOnScreenIconRect, fCIcon);
  465.             END; {QuickDrawStuff}
  466.     
  467.         BEGIN {RenderIcon}
  468.             gOffscreenManager.Draw(QuickDrawStuff)
  469.         END; {RenderIcon}
  470.     
  471.     PROCEDURE CopyToScreen;
  472.  
  473.     {    Blast the offscreen fScreenLocusImage back to the screen. }
  474.  
  475.     {$IFC qDebug}
  476.         VAR
  477.             screenManagerScreenRect, onScreenRestoreRect: Rect;
  478.     {$ENDC}
  479.  
  480.         BEGIN {CopyToScreen}
  481.  
  482.             gOffscreenManager.CopyBitsToScreen(srcCopy, NIL);
  483.  
  484.         {$IFC qDebug}
  485.             IF gIntenseDebugging THEN  { Show, in the upper left of the screen, what's around the icon. }
  486.                 BEGIN
  487.                     SetRect(onScreenRestoreRect,
  488.                             0,
  489.                             0,
  490.                             kIconWidth - (2 * kInsetWidth),
  491.                             kIconHeight - (2 * kInsetHeight));
  492.                     screenManagerScreenRect := gOffScreenManager.fScreenRect;
  493.                     gOffscreenManager.CopyBitsTo(currPort^.portBits,
  494.                                                  onScreenRestoreRect,
  495.                                                  screenManagerScreenRect,
  496.                                                  srcCopy,
  497.                                                  NIL);
  498.                 END
  499.         {$ENDC}
  500.  
  501.         END; {CopyToScreen}
  502.  
  503.  
  504.     BEGIN {TCIconTracker.CIconTrack}
  505.         fThisTrackPoint := nextPoint;
  506.         Constrain;
  507.         GetPort(currPort);
  508.         CalculateRectangles;
  509.         GetLocusFromScreen;
  510.         IF NOT fFirstTime THEN
  511.             RestoreUnderOldIcon;
  512.         GetUnderNewIcon;
  513.         IF NOT fLastTime THEN
  514.             RenderIcon;
  515.         CopyToScreen;
  516.         fLastTrackPoint := fThisTrackPoint
  517.     END; {TCIconTracker.CIconTrack}
  518.  
  519.  
  520. { :::::::::::::     TInterViewTracker     ::::::::::::::: }
  521.  
  522.  
  523. {$S ASelCommand}
  524. PROCEDURE TInterViewTracker.IInterViewTracker (aTrackingView: TView; offset: Point);
  525.  
  526.     VAR
  527.         anIcon: CIconhandle;
  528.         fi: FailInfo;
  529.  
  530.     PROCEDURE HandleFailure (error: OSErr; message: LONGINT);
  531.     
  532.         BEGIN {HandleFailure}
  533.             SELF.ICIconTracker(cIconTrackerCmd, NIL, NIL, NIL, NIL);
  534.             SELF.Free;
  535.         END; {HandleFailure}
  536.     
  537.     BEGIN {TInterViewTracker.IInterViewTracker}
  538.  
  539.         fTrackingWindow := aTrackingView.GetWindow;
  540.         fTrackingView := aTrackingView;
  541.         fMouseDownOffset := offset;
  542.         fReleasePoint := gZeroVPt;
  543.  
  544.     {    Note that this is slightly unusual.  Normally you don't do operations that
  545.         allocate memory until after the superclass's initialization method is called.
  546.         However, in this case, TCIconTracker needs the cicn for it to properly complete
  547.         it's initialization.  Hence, if the cicn can't be found or allocated, then 
  548.         we need to finish the TCicon initialization so that we can free the
  549.         TInterViewTracker.                                                                    }
  550.         
  551.         CatchFailures(fi, HandleFailure);
  552.         anIcon := SELF.GetCIconHandle;
  553.         Success(fi);
  554.  
  555.     {    NOTE:  If components ever free their icons we should pass a copy to ICIconTracker
  556.         since TCIconTracker will free it also.                                                }
  557.         
  558.         SELF.ICIconTracker(cIconTrackerCmd, NIL, NIL, NIL, anIcon);
  559.         fViewConstrain := FALSE
  560.  
  561.     END; {TInterViewTracker.IInterViewTracker}
  562.  
  563.  
  564. {$S AFields}
  565. PROCEDURE TInterViewTracker.Fields (PROCEDURE DoToField (fieldName: Str255;
  566.                                                          fieldAddr: Ptr;
  567.                                                          fieldType: INTEGER));
  568. OVERRIDE;
  569.  
  570.     BEGIN {TInterViewTracker.Fields}
  571.         DoToField('TInterViewTracker', NIL, bClass);
  572.         DoToField('fTrackingWindow', @fTrackingWindow, bObject);
  573.         DoToField('fTrackingView', @fTrackingView, bObject);
  574.         DoToField('fMouseDownOffset', @fMouseDownOffset, bPoint);
  575.         DoToField('fReleasePoint', @fReleasePoint, bVPoint);
  576.         INHERITED Fields(DoToField);
  577.     END; {TInterViewTracker.Fields}
  578.  
  579.  
  580. {$S ASelCommand}
  581. FUNCTION  TInterViewTracker.GetCIconHandle: CIconHandle;
  582.     BEGIN
  583.     {    Subclasses of TInterViewTracker should override this method to get their cicn.
  584.         Some subclasses will store the resource number of the cicn and use the ToolBox
  585.         call "GetCIcon", others will record the cicn's name and used "Get1NamedResource",
  586.         etc.                                                                                }
  587.         
  588.         GetCIconHandle := NIL;
  589.  
  590.         {$IFC qDebug}
  591.         WriteLn('TInterViewTracker.GetCIconHandle was not overridden');
  592.         {$ENDC}
  593.     
  594.     END;
  595.  
  596.  
  597. { Mouse handling }
  598. {$S ADoCommand}
  599. FUNCTION TInterViewTracker.TrackMouse (aTrackPhase: TrackPhase;
  600.                                        VAR anchorPoint, previousPoint, nextPoint: VPoint;
  601.                                        mouseDidMove: BOOLEAN): TCommand;
  602. OVERRIDE;
  603.  
  604.     VAR
  605.         aPoint: Point;
  606.         savedPort : GrafPtr;
  607.  
  608.     FUNCTION DesktopToLocal (aView: TView; aVPt: VPoint): VPoint;
  609.  
  610.     {    Takes aVPt in desktop coordinates and returns a VPoint in aView's coordinates. }
  611.  
  612.         CONST
  613.         
  614.             kFocusFailed = 'Focused Failed in TInterViewTracker.TrackMouse >> DesktopToLocal';
  615.  
  616.         VAR
  617.         
  618.             theVMouse : VPoint;
  619.             theMouse : Point;
  620.             savedPort : GrafPtr;
  621.             oldFocusedView : TView;
  622.             fi : FailInfo;
  623.  
  624.         PROCEDURE HandleFailure (error: OSErr; message: LONGINT);
  625.     
  626.             BEGIN {HandleFailure}
  627.                 SetPort(savedPort);
  628.             END; {HandleFailure}
  629.         
  630.         BEGIN {DesktopToLocal}
  631.     
  632.             IF aView <> NIL THEN
  633.                 BEGIN
  634.  
  635.                 {    When fView = NIL we're "focused" on the desktopPort.
  636.                     So save it before we focus on a view, so it can be restored.    }
  637.                      
  638.                     GetPort(savedPort);    { If we don't do this TApplication.Trackmouse gets confused. }
  639.     
  640.                     CatchFailures(fi, HandleFailure);
  641.                         gApplication.InvalidateFocus;  { MacApp gets confused when tracking on the desktop. }
  642.                         Assertion(aView.Focus, AtStr(kFocusFailed));
  643.                     Success(fi);
  644.     
  645.                     theVMouse := aVPt;
  646.                     theMouse := VPtToPt(theVMouse);
  647.                     GlobalToLocal(theMouse);
  648.                     PtToVPt(theMouse, theVMouse);
  649.                     DesktopToLocal := theVMouse;
  650.                     
  651.                 {    Restore the desktopPort.    }
  652.                     gApplication.InvalidateFocus;
  653.                     SetPort(savedPort)
  654.                     
  655.                 END
  656.             ELSE
  657.                 DesktopToLocal := aVPT
  658.     
  659.         END; {DesktopToLocal}
  660.     
  661.     PROCEDURE NextView (aVPt: VPoint);
  662.  
  663.     {    Returns the next tracking view, NIL if on desktop. }
  664.  
  665.         VAR
  666.         
  667.             theMouse : Point;
  668.             aWMgrWindow : WindowPtr;
  669.             trackingView : TView;
  670.             thisView : TView;
  671.             thisWindow : TWindow;
  672.  
  673.         FUNCTION ContainsPt (aView: TView): BOOLEAN;
  674.  
  675.         {    Does this view contain the current tracking point?  Used as an iterator. }
  676.  
  677.             VAR
  678.                 theVMouse: VPoint;
  679.  
  680.             BEGIN {ContainsPt}
  681.                 theVMouse := DesktopToLocal(aView.GetWindow, aVPt);
  682.                 aView.WindowToLocal(theVMouse);
  683.                 ContainsPt := aView.ContainsMouse(theVMouse);
  684.             END; {ContainsPt}
  685.     
  686.         FUNCTION LastViewUnderPt (aView: TView): TView;
  687.  
  688.         {    Recursively determine the topmost view under the current tracking point. }
  689.  
  690.             VAR
  691.                 subView: TView;
  692.     
  693.             BEGIN {LastViewUnderPt}
  694.                 LastViewUnderPt := aView;
  695.                 subView := aView.LastSubViewThat(ContainsPt);
  696.                 IF subView <> NIL THEN
  697.                     LastViewUnderPt := LastViewUnderPt(subView)
  698.             END; {LastViewUnderPt}
  699.         
  700.         BEGIN {NextView}
  701.     
  702.             theMouse := VPtToPt(aVPt);
  703.             IF FindWindow(theMouse, aWMgrWindow) = inContent THEN    { We're in a window. }
  704.                 BEGIN
  705.                     thisWindow := gApplication.WMgrToWindow(aWMgrWindow);
  706.                     IF thisWindow = NIL THEN    { Not a MacApp Window. }
  707.                         thisView := NIL
  708.                     ELSE IF thisWindow = fTrackingWindow THEN    { A MacApp Window and same as last time. }
  709.                         IF ContainsPt(fTrackingView) THEN    { Same view as last time. }
  710.                             thisView := LastViewUnderPt(fTrackingView)
  711.                         ELSE    { Different view from last time. }
  712.                             thisView := LastViewUnderPt(thisWindow)
  713.                     ELSE    { Different window from last time. }
  714.                         thisView := LastViewUnderPt(thisWindow)
  715.                 END
  716.             ELSE    { Not in a window. }
  717.                 BEGIN
  718.                     thisWindow := NIL;
  719.                     thisView := NIL
  720.                 END;
  721.                 
  722.             fTrackingWindow := thisWindow;
  723.             fTrackingView := thisView
  724.     
  725.         END; {NextView}
  726.     
  727.     BEGIN {TInterViewTracker.TrackMouse}
  728.  
  729.         TrackMouse := INHERITED TrackMouse(aTrackPhase,
  730.                                            anchorPoint,
  731.                                            previousPoint,
  732.                                            nextPoint,
  733.                                            mouseDidMove);
  734.                                            
  735.         IF (aTrackPhase = trackMove) & mouseDidMove THEN
  736.             NextView(nextPoint)    { Get the current fTrackingView and fTrackingWindow under the tracking point. }
  737.         ELSE IF aTrackPhase = trackRelease THEN
  738.             IF fTrackingView <> NIL THEN
  739.                 fReleasePoint := DesktopToLocal(fTrackingView, nextPoint)
  740.             ELSE
  741.                 TrackMouse := gNoChanges;
  742.  
  743.     {    This has to go here because MacApp's mouse tracking
  744.         architecture wasn't intended for cross-view tracking.    }
  745.         
  746.         aPoint := VPtToPt(nextPoint);
  747.  
  748.     {    Do the coordinate translation and offset
  749.         then use TCIconTrackers tracking method.    }
  750.         
  751.         AddPt(fMouseDownOffset, aPoint);
  752.  
  753.         SELF.CIconTrack(aPoint)
  754.         
  755.     END; {TInterViewTracker.TrackMouse}
  756.  
  757.  
  758. {$S ADoCommand}
  759. PROCEDURE TInterViewTracker.DoIt;
  760. OVERRIDE;
  761.     
  762. {$IFC qDebug}
  763.     VAR
  764.         className : MAName;
  765. {$ENDC}
  766.  
  767.  
  768.     BEGIN {TInterViewTracker.DoIt}
  769.         IF fTrackingView <> NIL THEN
  770.             BEGIN
  771.                 gApplication.InvalidateFocus;  { MacApp gets confused when tracking on the desktop. }
  772.  
  773.             {    This is gross but nececessary because we don't have multiple
  774.                 inheritance and not everything can be a subclass of TTrackingView.    }
  775.                 
  776.             {$IFC qDebug}
  777.                 WRITE('fTrackingView is a ');
  778.                 IF fTrackingView <> NIL THEN
  779.                     BEGIN
  780.                         fTrackingView.GetClassName(className);
  781.                         WRITELN(className)
  782.                     END
  783.                 ELSE
  784.                     WRITELN('NIL');
  785.             {$ENDC}
  786.  
  787.                     
  788.             {    Probably you will want to override this DoIt and test the membership
  789.                 of the view onto which the icon was dropped.  This is groddy, but without
  790.                 multilple inheritance....
  791.                 
  792.                 Your code might look like this: 
  793.                 
  794.                 VAR
  795.                     releasePoint : VPoint;
  796.                     
  797.                 releasePoint := fReleasePoint;
  798.  
  799.                 IF MEMBER(fTrackingView, TCGridView1) THEN
  800.                     TMyView1(fTrackingView).PlaceIcon(fIconNumber, releasePoint, PlaceIt)
  801.                 ELSE IF MEMBER(fTrackingView, TCGridView2) THEN
  802.                     TMyView2(fTrackingView).PlaceIcon(fIconNumber, releasePoint, PlaceIt)                    
  803.                 ELSE IF MEMBER(fTrackingView, TCGridView2) THEN
  804.                     TMyView3(fTrackingView).SomeOtherMethod(fIconNumber,  PlaceIt)                    }
  805.  
  806.             END
  807.             
  808.     END; {TInterViewTracker.DoIt}
  809.  
  810.  
  811. { :::::::::::::     TPlaceByNumber     ::::::::::::::: }
  812.  
  813.  
  814. {$S ASelCommand}
  815. PROCEDURE TPlaceByNumber.IPlaceByNumber (aTrackingView: TView;
  816.                                          offset: Point;
  817.                                          anIconNumber: IconNumber);
  818.  
  819.     BEGIN {TPlaceByNumber.IPlaceByNumber}
  820.         fIconNumber := anIconNumber;
  821.         SELF.IInterViewTracker(aTrackingView, offset);
  822.     END; {TPlaceByNumber.IPlaceByNumber}
  823.  
  824.  
  825. {$S AFields}
  826. PROCEDURE TPlaceByNumber.Fields (PROCEDURE DoToField (fieldName: Str255;
  827.                                                       fieldAddr: Ptr;
  828.                                                       fieldType: INTEGER));
  829. OVERRIDE;
  830.  
  831.     BEGIN {TPlaceByNumber.Fields}
  832.         DoToField('TPlaceByNumber', NIL, bClass);
  833.         DoToField('fIconNumber', @fIconNumber, bInteger);
  834.         INHERITED Fields(DoToField);
  835.     END; {TPlaceByNumber.Fields}
  836.  
  837.  
  838. {$S ASelCommand}
  839. FUNCTION  TPlaceByNumber.GetCIconHandle: CIconHandle;
  840. OVERRIDE;
  841.  
  842.     VAR
  843.         tempCIcon:    CIconHandle;
  844.         
  845.     BEGIN
  846.         tempCIcon := GetCIcon(fIconNumber);
  847.         FailNILResource(tempCIcon);    
  848.         GetCIconHandle := tempCIcon;        
  849.     END;
  850.  
  851.  
  852. {$S ADoCommand}
  853. PROCEDURE TPlaceByNumber.DoIt;
  854. OVERRIDE;
  855.     
  856.     VAR
  857.         releasePoint : VPoint;
  858.  
  859.     BEGIN {TPlaceByNumber.DoIt}
  860.         INHERITED DoIt;
  861.         
  862.         IF fTrackingView <> NIL THEN
  863.             BEGIN
  864.                 releasePoint := fReleasePoint;
  865.  
  866.                 IF MEMBER(fTrackingView, TTrackingView) THEN
  867.                     TTrackingView(fTrackingView).PlaceIcon(fIconNumber, releasePoint, PlaceIt);
  868.                     
  869.             {    Probably you will want to override this DoIt and test the membership
  870.                 of the view onto which the icon was dropped.  This is groddy, but without
  871.                 multilple inheritance....
  872.                 
  873.                 Your code might look like this: 
  874.                 
  875.                 IF MEMBER(fTrackingView, TCGridView1) THEN
  876.                     TMyView1(fTrackingView).PlaceIcon(fIconNumber, releasePoint, PlaceIt)
  877.                 ELSE IF MEMBER(fTrackingView, TCGridView2) THEN
  878.                     TMyView2(fTrackingView).PlaceIcon(fIconNumber, releasePoint, PlaceIt)                    
  879.                 ELSE IF MEMBER(fTrackingView, TCGridView2) THEN
  880.                     TMyView3(fTrackingView).SomeOtherMethod(fIconNumber,  PlaceIt)                    }
  881.  
  882.             END;
  883.     END; {TPlaceByNumber.DoIt}
  884.  
  885.  
  886. {$S ADoCommand}
  887. PROCEDURE TPlaceByNumber.UndoIt;
  888. OVERRIDE;
  889.  
  890.     VAR
  891.         releasePoint : VPoint;
  892.  
  893.     BEGIN {TPlaceByNumber.UndoIt}
  894.         IF fTrackingView <> NIL THEN
  895.             BEGIN
  896.                 releasePoint := fReleasePoint;
  897.  
  898.             {    This is gross but nececessary because we don't have multiple
  899.                 inheritance and not everything can be a subclass of TTrackingView.    
  900.                 See comments in TPlaceByNumber.DoIt.                                  }
  901.                 
  902.                 IF MEMBER(fTrackingView, TTrackingView) THEN
  903.                     TTrackingView(fTrackingView).PlaceIcon(fIconNumber, releasePoint, UnPlaceIt);
  904.                     
  905.             END;
  906.     END; {TPlaceByNumber.UndoIt}
  907.  
  908.  
  909. {$S ADoCommand}
  910. PROCEDURE TPlaceByNumber.RedoIt;
  911. OVERRIDE;
  912.  
  913.     VAR
  914.         releasePoint : VPoint;
  915.  
  916.     BEGIN {TPlaceByNumber.RedoIt}
  917.         IF fTrackingView <> NIL THEN
  918.             BEGIN
  919.                 releasePoint := fReleasePoint;
  920.  
  921.             {    This is gross but nececessary because we don't have multiple
  922.                 inheritance and not everything can be a subclass of TTrackingView.    
  923.                 See comments in TPlaceByNumber.DoIt.                                  }
  924.                 
  925.                 
  926.                 IF MEMBER(fTrackingView, TTrackingView) THEN
  927.                     TTrackingView(fTrackingView).PlaceIcon(fIconNumber, releasePoint, RePlaceIt);
  928.  
  929.             END;
  930.     END; {TPlaceByNumber.RedoIt}
  931.  
  932.